#include "DataMgr.h"
#include "Node.h"
#include "Cxml.h"
#include "Common/Common.h"
#include "Common/FileIO.h"
#include "Common/Attribute.h"
#include "NFData/NFAttribute.h"
#include "TFIDF/TFIDF.h"
#include <iostream>
#include <sstream>
#include <afx.h>

using namespace std;

CDataMgr*	CDataMgr::m_ptrDataMgr = NULL;

CDataMgr::CDataMgr()
{
	m_bFlagCreate = false;
}

CDataMgr::~CDataMgr()
{
	if(m_bFlagCreate)
		Destroy();
}

bool CDataMgr::Create()
	{
	if(m_bFlagCreate)
		return false;

	m_LoadData();
	m_LoadEmotion();

	m_ptrTFIDF = new CTFIDF;

	m_InitTFIDF();

	m_bFlagCreate = true;

	return true;
}

bool CDataMgr::Destroy()
{
	if(!m_bFlagCreate)
		return false;

	m_dataSet.clear();

	SAFE_DELETE(m_ptrTFIDF);

	m_bFlagCreate = false;

	return true;
}

vector<pair<int, float> > CDataMgr::Query(std::string query)
{
	return m_ptrTFIDF->SimilarDocs(query);
}

bool CDataMgr::GetData(unsigned int nID, NetflixDataElement& data)
{
	if(nID > NUMOFDATA)
		return false;

	data = m_dataSet[nID];

	return true;
}

CDataMgr* CDataMgr::Instance()
{
	if(!m_ptrDataMgr)
		m_ptrDataMgr = new CDataMgr;

	return m_ptrDataMgr;
}

void CDataMgr::m_InitTFIDF()
{
	vector<string> documents;

	for(int i = 0; i < m_dataSet.size(); i++)
	{
		NetflixDataElement& element = m_dataSet[i];
		
		documents.push_back(element.Content2Str());
	}

	m_ptrTFIDF->Create(documents);
}

void CDataMgr::m_LoadData()
{
	int				nCnt;
	TCHAR			szFilename[256];
	stringstream	ss;

	for(nCnt = 0; nCnt < NUMOFDATA; nCnt++)
	{
		CString filename;
		NetflixDataElement netflix;

		filename.Format(L".\\Data\\%d.xml", nCnt + 1);
		_tcscpy(szFilename, filename);

		netflix = t_ReadFile(szFilename, nCnt);
		m_dataSet.push_back(netflix);
	}
}

void CDataMgr::m_LoadEmotion()
{
	CFileIO	file;
	
	for(int i = 0; i < NUMOFDATA; i++)
	{
		stringstream	ss;
		char			szBuffer[1024];
		vector<UserComment>&	comments = m_dataSet[i].getUserComments();
		int				nCnt = 0;
		float			avg = 0;

		ss << "emotion\\" << (i + 1) << "-2.txt";

		file.Create(ss.str().c_str());

		while(file.ReadLine(szBuffer))
		{
			if(strncmp(szBuffer, "<review>", 8) == 0)
			{
				avg = 0;
				continue;
			}
			else if(strncmp(szBuffer, "</review>", 9) == 0)
			{
				comments[nCnt].SetAvgEmotion(avg);
				nCnt++;
				continue;
			}
			else
			{
				CAttribute		attr(szBuffer, " \r\n");
				vector<string>	list = attr.List();

				int emo = StringTo<int>(list[0]);
				float value = StringTo<float>(list[1]);

				// positive 0, negative 1
				emo = (emo == 3 || emo == 5) ? 0 : 1;
				value = (emo == 1) ? -value : value;

				comments[nCnt].AddEmotion(value);
				avg += value;
			}
		}
		file.Destroy();
	}
}

NetflixDataElement CDataMgr::t_ReadFile(TCHAR* fName, int movieId) 
{
	CFile* fp = new CFile(fName, CFile::modeRead);
	_TCHAR c_arr[101] = {0};
	CString	CszXML = _T("");

	while(1)
	{
		memset(c_arr, 0, 100);
		if(fp->Read(c_arr, 100) < 100)
		{
			CszXML.Append(c_arr);
			break;
		}
		CszXML.Append(c_arr);
	}

	fp->Close();
	delete(fp);
	Cxml *xml = new  Cxml();
	xml->ParseString(CszXML.GetBuffer());
	CNode* pRoot = xml->GetRootNode();

	CString szText= _T("");
	szText.Append(pRoot->GetName());
	szText.Append( _T(" - "));
	szText.Append(pRoot->GetValue());

	vector<CNode*> nodes;
	t_Parse(pRoot, nodes);

	vector<string> directors;
	vector<string> castMembers;
	vector<string> genres;

	vector<UserComment> userComments;

	string title;

	int numUserRatings = 0;

	double netflixRating = 0;

	for(size_t n = 0; n < nodes.size(); n++) {
		CNode* node = nodes[n];

		CString descCStr= _T("");
		descCStr.Append(node->GetName());
		string desc = t_ConvertCStringToString(descCStr);

		if(desc == "UserReview") {
			CNode* one = nodes[n+1];
			CNode* two = nodes[n+2];
			CNode* three = nodes[n+3];

			CString descCStr= _T("");
			descCStr.Append(one->GetValue());
			string comment = t_ConvertCStringToString(descCStr);

			descCStr = _T("");
			descCStr.Append(two->GetValue());
			string helpfulness = t_ConvertCStringToString(descCStr);

			descCStr = _T("");
			descCStr.Append(three->GetValue());
			string rating = t_ConvertCStringToString(descCStr);

			istringstream i(rating);
			double dRating;
			i >> dRating;

			UserComment uComment(dRating, helpfulness, comment);
			userComments.push_back(uComment);

			n += 3;

		}
		else if(desc == "Genre") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string genre = t_ConvertCStringToString(descCStr);
			genres.push_back(genre);
		}
		else if(desc == "NumUserRatings") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string userRatings = t_ConvertCStringToString(descCStr);

			istringstream i(userRatings);
			int dRating;
			i >> dRating;

			numUserRatings = dRating;
		}
		else if(desc == "NetflixRating") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string netflixR = t_ConvertCStringToString(descCStr);

			istringstream i(netflixR);
			double dRating;
			i >> dRating;

			netflixRating = dRating;
		}
		else if(desc == "CastMember") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string cast = t_ConvertCStringToString(descCStr);

			castMembers.push_back(cast);
		}
		else if(desc == "Director") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string dir = t_ConvertCStringToString(descCStr);

			directors.push_back(dir);
		}
		else if(desc == "Release") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string release = t_ConvertCStringToString(descCStr);
		}
		else if(desc == "Title") {
			descCStr = _T("");
			descCStr.Append(node->GetValue());
			string dTitle = t_ConvertCStringToString(descCStr);

			title = dTitle;
		}
		else {
			//cout << "Else: " << desc << endl;
		}

		CString valueCStr= _T("");
		valueCStr.Append(node->GetValue());
		string value = t_ConvertCStringToString(valueCStr);
	}

	NetflixDataElement element(title, directors, castMembers, genres, userComments, netflixRating, movieId);
	return element;
}

string CDataMgr::t_ConvertCStringToString(CString cStr) 
{
	CT2CA pszConvertedAnsiString (cStr);
	std::string strStd (pszConvertedAnsiString);
	return strStd;
}

void CDataMgr::t_Parse(CNode* pNode, vector<CNode*> &parsedStrs)
{
	if(!pNode)
		return ;

	while(1)
	{
		CNode* pChild = pNode->GetNextChild();
		if(!pChild)
			return ;
		parsedStrs.push_back(pChild);
		t_Parse(pChild, parsedStrs);
	}
}

void CDataMgr::t_Fill(CNode* pNode)
{
	if(!pNode)
		return ;
	CNFAttribute *a = NULL;
	CString szText= _T("");
	szText.Append(pNode->GetName());
	szText.Append( _T(" - "));
	szText.Append(pNode->GetValue());
	wcout << szText.GetBuffer() << endl;
	while((a=pNode->GetNextAttribute()) != NULL)
	{
		szText.Append(_T(" _ "));
		szText.Append(a->GetName());
		szText.Append(_T(" = "));
		szText.Append(a->GetValue());
		wcout << szText.GetBuffer(szText.GetLength()) << endl;
	}

	while(1)
	{
		CNode* pChild = pNode->GetNextChild();
		if(!pChild)
			return ;

		t_Fill(pChild);
	}
}
